﻿using Language.Utility;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities;
using System;
using System.ComponentModel.Composition;
using System.Runtime.InteropServices;

namespace Language.Intellisense.SmartIndent
{
    internal class CommandHandler : IOleCommandTarget
    {
        #region Private Data

        private IOleCommandTarget _textViewAdapterCommandHandler;
        private ITextView _textView;
        private Settings _settings;

        #endregion Private Data

        #region C-Tor

        public CommandHandler( IVsTextView textViewAdapter, ITextView textView, Settings settings )
        {
            _textView = textView;
            _settings = settings;

            //add the command to the command chain
            textViewAdapter.AddCommandFilter( this, out _textViewAdapterCommandHandler );
        }

        #endregion C-Tor
        
        #region IOleCommandTarget

        int IOleCommandTarget.Exec( ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut )
        {
            //pass along the command so the char is added to the buffer
            int retVal = _textViewAdapterCommandHandler.Exec( ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut );

            if ( !_settings.IsSmartIndentationEnabled )
                return retVal;

            if ( pguidCmdGroup != VSConstants.VSStd2K )
                return retVal;

            if ( nCmdID != (uint)VSConstants.VSStd2KCmdID.TYPECHAR )
                return retVal;

            char typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant( pvaIn );

            if ( typedChar == '}' )
            {
                _textView.ReformatIndentationAtCaret();
            }

            return retVal;
        }

        int IOleCommandTarget.QueryStatus( ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText )
        {
            if ( _settings.IsSmartIndentationEnabled )
            {
                if ( pguidCmdGroup == VSConstants.VSStd2K )
                {
                    for ( uint i = 0; i < prgCmds.Length; ++i )
                    {
                        VSConstants.VSStd2KCmdID id = (VSConstants.VSStd2KCmdID)prgCmds[ i ].cmdID;

                        switch ( id )
                        {
                            case VSConstants.VSStd2KCmdID.TYPECHAR:
                                prgCmds[ i ].cmdf = (uint)OLECMDF.OLECMDF_SUPPORTED;
                                return VSConstants.S_OK;
                        }
                    }
                }
            }

            return _textViewAdapterCommandHandler.QueryStatus( ref pguidCmdGroup, cCmds, prgCmds, pCmdText );
        }

        #endregion IOleCommandTarget
    }

    #region Provider

    [Export( typeof( IVsTextViewCreationListener ) )]
    [Name( "Closing Brace Formatter" )]
    [ContentType( "redscript" )]
    [TextViewRole( PredefinedTextViewRoles.Editable )]
    internal class CommandHandlerProvider : IVsTextViewCreationListener
    {
        #region Imports

        [Import]
        internal IVsEditorAdaptersFactoryService AdapterService = null;

        [Import]
        private Settings _settings = null;

        #endregion Imports

        #region IVsTextViewCreationListener

        void IVsTextViewCreationListener.VsTextViewCreated( IVsTextView textViewAdapter )
        {
            ITextView textView = AdapterService.GetWpfTextView( textViewAdapter );
            if ( textView == null )
                return;
            
            Func<CommandHandler> createCommandHandler = delegate () { return new CommandHandler( textViewAdapter, textView, _settings ); };
            textView.Properties.GetOrCreateSingletonProperty( createCommandHandler );
        }

        #endregion IVsTextViewCreationListener
    }

    #endregion Provider
}
